namespace V2TEK.NET.SH.Silverlight.Calendar
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Runtime.CompilerServices;

    [Description("Enables to store working and non working times for a project, activity or resource."), TypeConverter("ILOG.Views.Gantt.Windows.Forms.Design.CalendarTypeConverter, ILOG.Gantt.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=7906592bc7cc7340")]
    public class WorkCalendar
    {
        private WorkCalendar _baseCalendar;
        internal Calendar _calendar;
        private bool _disableevents;
        private bool _initializing;
        private string _name;
        private List<Period> _periods;
        private List<WeakReference> _subCalendars;
        private WorkingDay[] _workingDays;
        private static readonly object CalendarChangedKey = new object();
        private static readonly object CalendarNameChangedKey = new object();
        public static readonly WorkCalendar NightShift = CreateNightShift();
        internal static readonly long OneDay = TimeSpan.FromDays(1.0).Ticks;
        public static readonly WorkCalendar Standard = CreateStandard();
        public static readonly WorkCalendar TwentyFourHours = Create24Hours();

        private event EventHandler _changed;

        private event EventHandler _nameChanged;

        [Category("Property Changed"), Description("Occurs when the CalendarName property has changed on the calendar.")]
        public event EventHandler CalendarNameChanged
        {
            add
            {
                if (!this.IsPredefinedCalendar)
                {
                    this._nameChanged = (EventHandler) Delegate.Combine(this._nameChanged, value);
                }
            }
            remove
            {
                if (!this.IsPredefinedCalendar)
                {
                    this._nameChanged = (EventHandler) Delegate.Remove(this._nameChanged, value);
                }
            }
        }

        [Description("Occurs when the calendar has changed.")]
        public event EventHandler Changed
        {
            add
            {
                if (!this.IsPredefinedCalendar)
                {
                    this._changed = (EventHandler) Delegate.Combine(this._changed, value);
                }
            }
            remove
            {
                if (!this.IsPredefinedCalendar)
                {
                    this._changed = (EventHandler) Delegate.Remove(this._changed, value);
                }
            }
        }

        public WorkCalendar() : this("Default", Standard)
        {
        }

        public WorkCalendar(string name) : this(name, Standard)
        {
        }

        public WorkCalendar(string name, WorkCalendar baseCalendar)
        {
            if ((baseCalendar != null) && !baseCalendar.IsBaseCalendar)
            {
                throw new ArgumentException("specified base calendar is not a base calendar");
            }
            this._name = name;
            this._periods = new List<Period>(2);
            this._calendar = CultureInfo.CurrentCulture.Calendar;
            this._workingDays = new WorkingDay[7];
            this._baseCalendar = baseCalendar;
            if (this._baseCalendar != null)
            {
                this._baseCalendar.AddSubcalendar(this);
            }
            if (this.IsBaseCalendar)
            {
                for (int i = 0; i < 7; i++)
                {
                    DayOfWeek d = (DayOfWeek) i;
                    this._workingDays[i] = CreateDefaultWorkingDay(this, d);
                    this._workingDays[i].Standard = true;
                }
            }
            else
            {
                this.InheritBasePeriods();
            }
        }

        public DateTime Add(DateTime time, TimeSpan work)
        {
            try
            {
                long ticks = work.Ticks;
                if (ticks > 0L)
                {
                    goto Label_00D8;
                }
                return time;
            Label_0018:
                time = this.NextWorkingTime(time);
                if (!this.HasNextWorkingTime(time))
                {
                    return time;
                }
                Period period = this.GetPeriod(time);
                if (period != null)
                {
                    time = period.Add(time, ref ticks);
                }
                else
                {
                    period = this.NextPeriod(time);
                    long duration = ticks;
                    if (period != null)
                    {
                        long num3 = this.StandardWorkBetween(time, period.StartDate);
                        duration = Math.Min(ticks, num3);
                    }
                    ticks -= duration;
                    long workInOneWeek = this.WorkInOneWeek;
                    if ((workInOneWeek != 0L) && (duration >= workInOneWeek))
                    {
                        long num5 = duration / workInOneWeek;
                        if ((duration % workInOneWeek) == 0L)
                        {
                            num5 -= 1L;
                        }
                        time = time.AddDays((double) (7L * num5));
                        duration -= num5 * workInOneWeek;
                    }
                    while (duration != 0L)
                    {
                        time = this.NextWorkingTime(time);
                        time = this.GetWorkingDay(time).Add(time, ref duration);
                    }
                }
            Label_00D8:
                if (ticks != 0L)
                {
                    goto Label_0018;
                }
                return time;
            }
            catch (Exception)
            {
                return DateTime.MaxValue;
            }
        }

        private void AddSubcalendar(WorkCalendar cal)
        {
            if (!this.IsPredefinedCalendar)
            {
                if (this._subCalendars == null)
                {
                    this._subCalendars = new List<WeakReference>();
                }
                this._subCalendars.Add(new WeakReference(cal));
            }
        }

        private void AssertNotReadOnly()
        {
            if (this.IsPredefinedCalendar)
            {
                throw new InvalidOperationException("Changing this calendar is not allowed");
            }
        }

        public void BeginInit()
        {
            this._initializing = true;
        }

        private static void CheckWorkingTimes(WorkingTime[] times)
        {
            if ((times == null) || (times.Length == 0))
            {
                throw new ArgumentException("working times should not be empty");
            }
            for (int i = 1; i < times.Length; i++)
            {
                if (times[i].StartTime <= times[i - 1].EndTime)
                {
                    throw new ArgumentException("working times are badly specified");
                }
            }
        }

        public object Clone()
        {
            WorkCalendar calendar = new WorkCalendar(this.CalendarName, this.BaseCalendar) {
                _periods = new List<Period>(this.Periods.Count)
            };
            foreach (Period period in this.Periods)
            {
                calendar.Periods.Add(period.Clone() as Period);
            }
            calendar._workingDays = (WorkingDay[]) this._workingDays.Clone();
            for (int i = 0; i < 7; i++)
            {
                if (this._workingDays[i] != null)
                {
                    calendar._workingDays[i] = (WorkingDay) this._workingDays[i].Clone();
                }
            }
            return calendar;
        }

        public void CopyFrom(WorkCalendar cal)
        {
            this.AssertNotReadOnly();
            for (int i = 0; i < 7; i++)
            {
                WorkingDay day = cal._workingDays[i];
                this._workingDays[i] = (day != null) ? ((WorkingDay) day.Clone()) : null;
            }
            this.Periods.Clear();
            foreach (Period period in cal.Periods)
            {
                this.Periods.Add(period.Clone() as Period);
            }
            if (cal.BaseCalendar != this.BaseCalendar)
            {
                this.InheritBasePeriods();
            }
            this.OnChanged(EventArgs.Empty);
        }

        private static WorkCalendar Create24Hours()
        {
            WorkCalendar calendar = new WorkCalendar("24 Hours", null);
            WorkingTime[] times = new WorkingTime[] { new WorkingTime(new TimeSpan(0L), TimeSpan.FromHours(24.0)) };
            for (int i = 0; i < 7; i++)
            {
                calendar.SetWorkingTimes((DayOfWeek) i, times);
            }
            return calendar;
        }

        internal static WorkingDay CreateDefaultWorkingDay(WorkCalendar cal, DayOfWeek d)
        {
            return new WorkingDay(cal, (d != DayOfWeek.Saturday) && (d != DayOfWeek.Sunday), d);
        }

        private static WorkCalendar CreateNightShift()
        {
            WorkCalendar calendar = new WorkCalendar("Night Shift", null);
            calendar.SetNonWorking(DayOfWeek.Sunday);
            WorkingTime[] times = new WorkingTime[] { new WorkingTime(TimeSpan.FromHours(23.0), TimeSpan.FromHours(24.0)) };
            calendar.SetWorkingTimes(DayOfWeek.Monday, times);
            times = new WorkingTime[] { new WorkingTime(new TimeSpan(0L), TimeSpan.FromHours(3.0)), new WorkingTime(TimeSpan.FromHours(4.0), TimeSpan.FromHours(8.0)), new WorkingTime(TimeSpan.FromHours(23.0), TimeSpan.FromHours(24.0)) };
            calendar.SetWorkingTimes(DayOfWeek.Tuesday, times);
            calendar.SetWorkingTimes(DayOfWeek.Wednesday, times);
            calendar.SetWorkingTimes(DayOfWeek.Thursday, times);
            calendar.SetWorkingTimes(DayOfWeek.Friday, times);
            times = new WorkingTime[] { new WorkingTime(new TimeSpan(0L), TimeSpan.FromHours(3.0)), new WorkingTime(TimeSpan.FromHours(4.0), TimeSpan.FromHours(8.0)) };
            calendar.SetWorkingTimes(DayOfWeek.Saturday, times);
            return calendar;
        }

        private static WorkCalendar CreateStandard()
        {
            return new WorkCalendar("Standard", null);
        }

        public void EndInit()
        {
            this._initializing = false;
        }

        public bool Equals(WorkCalendar obj)
        {
            if (obj == this)
            {
                return true;
            }
            WorkCalendar calendar = obj;
            return ((((calendar._baseCalendar == this._baseCalendar) && (calendar._name == this._name)) && SameWorkingDays(calendar._workingDays, this._workingDays)) && SamePeriods(calendar._periods, this._periods));
        }

        internal CalendarPeriod GetCalendarPeriod(DateTime time)
        {
            CalendarPeriod period = this.GetPeriod(time);
            if (period != null)
            {
                return period;
            }
            return this.GetWorkingDay(this._calendar.GetDayOfWeek(time));
        }

        private Period GetPeriod(DateTime time)
        {
            int count = this._periods.Count;
            if (count != 0)
            {
                DateTime date = time.Date;
                for (int i = 0; i < count; i++)
                {
                    Period period = this._periods[i];
                    if (date < period.StartDate)
                    {
                        break;
                    }
                    if (date <= period.EndDate)
                    {
                        return period;
                    }
                }
            }
            return null;
        }

        private Period GetPeriodBackWard(DateTime time)
        {
            int count = this._periods.Count;
            if (count != 0)
            {
                DateTime date = time.Date;
                for (int i = 0; i < count; i++)
                {
                    Period period = this._periods[i];
                    if (time <= period.StartDate)
                    {
                        break;
                    }
                    if (time <= period.EndDate.AddDays(1.0))
                    {
                        return period;
                    }
                }
            }
            return null;
        }

        public WorkingPeriod[] GetPeriods()
        {
            List<WorkingPeriod> list = new List<WorkingPeriod>();
            foreach (Period period in this._periods)
            {
                if (!period.Standard)
                {
                    list.Add(new WorkingPeriod(period.StartDate, period.EndDate, period.IsWorking, period.GetWorkingTimes()));
                }
            }
            return list.ToArray();
        }

        private WorkingDay GetWorkingDay(DateTime time)
        {
            return this.GetWorkingDay(time.DayOfWeek);
        }

        private WorkingDay GetWorkingDay(DayOfWeek dow)
        {
            WorkingDay day = this._workingDays[(int) dow];
            if (day == null)
            {
                return this._baseCalendar._workingDays[(int) dow];
            }
            return day;
        }

        private WorkingDay GetWorkingDayBackward(DateTime time)
        {
            if (!(time == time.Date))
            {
                return this.GetWorkingDay(time.DayOfWeek);
            }
            int num = ((int) time.DayOfWeek) - 1;
            if (num == -1)
            {
                num = 6;
            }
            return this.GetWorkingDay((DayOfWeek) num);
        }

        public WorkingTime[] GetWorkingTimes(DateTime date)
        {
            return this.GetCalendarPeriod(date.Date).GetWorkingTimes();
        }

        public WorkingTime[] GetWorkingTimes(DayOfWeek dayOfWeek)
        {
            return this.GetWorkingDay(dayOfWeek).GetWorkingTimes();
        }

        public bool HasNextNonWorkingTime(DateTime time)
        {
            try
            {
                for (int i = 0; i < 7; i++)
                {
                    if (!this.GetWorkingDay((DayOfWeek) i).Is24HoursWork())
                    {
                        return true;
                    }
                }
                int count = this._periods.Count;
                for (int j = 0; j < count; j++)
                {
                    Period period = this._periods[j];
                    DateTime date = time.Date;
                    if (date <= period.EndDate)
                    {
                        if (!period.IsWorking)
                        {
                            return true;
                        }
                        if (!period.Is24HoursWork())
                        {
                            if (date < period.EndDate)
                            {
                                return true;
                            }
                            TimeSpan span = (TimeSpan) (time - date);
                            long ticks = span.Ticks;
                            int num5 = period.WorkingTimes.Count;
                            for (int k = 0; k < num5; k++)
                            {
                                WorkingTime time3 = period.WorkingTimes[k];
                                if (ticks < time3._startTime)
                                {
                                    return true;
                                }
                                if (ticks <= time3._endTime)
                                {
                                    if (j == (count - 1))
                                    {
                                        return true;
                                    }
                                    if (time3._endTime != OneDay)
                                    {
                                        return true;
                                    }
                                }
                            }
                            return false;
                        }
                        time = period.EndDate.AddDays(1.0);
                    }
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public bool HasNextWorkingTime(DateTime time)
        {
            try
            {
                for (int i = 0; i < 7; i++)
                {
                    if (this.GetWorkingDay((DayOfWeek) i).IsWorking)
                    {
                        return true;
                    }
                }
                for (int j = this._periods.Count - 1; j >= 0; j--)
                {
                    Period period = this._periods[j];
                    DateTime date = time.Date;
                    if ((date <= period.EndDate) && period.IsWorking)
                    {
                        if (date < period.EndDate)
                        {
                            return true;
                        }
                        TimeSpan span = (TimeSpan) (time - date);
                        long ticks = span.Ticks;
                        for (int k = period.WorkingTimes.Count - 1; k >= 0; k--)
                        {
                            WorkingTime time3 = period.WorkingTimes[k];
                            if (ticks < time3._endTime)
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public bool HasPreviousWorkingTime(DateTime time)
        {
            try
            {
                for (int i = 0; i < 7; i++)
                {
                    if (this.GetWorkingDay((DayOfWeek) i).IsWorking)
                    {
                        return true;
                    }
                }
                for (int j = this._periods.Count - 1; j >= 0; j--)
                {
                    Period period = this._periods[j];
                    DateTime date = time.Date;
                    if (date < period.StartDate)
                    {
                        return false;
                    }
                    if (period.IsWorking)
                    {
                        if (date > period.StartDate)
                        {
                            return true;
                        }
                        TimeSpan span = (TimeSpan) (time - date);
                        long ticks = span.Ticks;
                        for (int k = period.WorkingTimes.Count - 1; k >= 0; k--)
                        {
                            WorkingTime time3 = period.WorkingTimes[k];
                            if (ticks >= time3._startTime)
                            {
                                return true;
                            }
                        }
                        return false;
                    }
                }
                return false;
            }
            catch (Exception)
            {
                return false;
            }
        }

        internal static bool HasStandardWorkingTimes(CalendarPeriod wd)
        {
            if (wd.WorkingTimes.Count == 2)
            {
                WorkingTime time = wd.WorkingTimes[0];
                if ((time.StartTime.TotalHours == 8.0) && (time.EndTime.TotalHours == 12.0))
                {
                    time = wd.WorkingTimes[1];
                    if ((time.StartTime.TotalHours == 13.0) && (time.EndTime.TotalHours == 17.0))
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public bool HasStandardWorkingTimes(DateTime date)
        {
            return HasStandardWorkingTimes(this.GetCalendarPeriod(date.Date));
        }

        public bool HasStandardWorkingTimes(DayOfWeek dayOfWeek)
        {
            return HasStandardWorkingTimes(this.GetWorkingDay(dayOfWeek));
        }

        private void InheritBasePeriods()
        {
            try
            {
                this._disableevents = true;
                Period[] array = new Period[this.Periods.Count];
                this.Periods.CopyTo(array, 0);
                this.Periods.Clear();
                foreach (Period period in this._baseCalendar.Periods)
                {
                    Period item = (Period) period.Clone();
                    item.Standard = true;
                    this.Periods.Add(item);
                }
                foreach (Period period3 in array)
                {
                    if (!period3.Standard)
                    {
                        if (!period3.IsWorking)
                        {
                            this.SetNonWorking(period3.StartDate, period3.EndDate);
                        }
                        else
                        {
                            WorkingTime[] timeArray = new WorkingTime[period3.WorkingTimes.Count];
                            period3.WorkingTimes.CopyTo(timeArray, 0);
                            this.SetWorkingTimes(period3.StartDate, period3.EndDate, timeArray);
                        }
                    }
                }
            }
            finally
            {
                this._disableevents = false;
            }
        }

        public bool IsDefaultDayOfWeek(DayOfWeek dayOfWeek)
        {
            if (this.IsBaseCalendar)
            {
                return this._workingDays[(int) dayOfWeek].Standard;
            }
            return (this._workingDays[(int) dayOfWeek] == null);
        }

        public bool IsDefaultWorkingDay(DateTime date)
        {
            if (!this.IsBaseCalendar)
            {
                return this.GetCalendarPeriod(date.Date).Standard;
            }
            CalendarPeriod calendarPeriod = this.GetCalendarPeriod(date.Date);
            if (calendarPeriod is WorkingDay)
            {
                return this.IsStandard(((WorkingDay) calendarPeriod).DayOfWeek);
            }
            return HasStandardWorkingTimes(calendarPeriod);
        }

        public bool IsDefaultWorkingDay(DayOfWeek dayOfWeek)
        {
            if (!this.IsBaseCalendar)
            {
                return this.GetWorkingDay(dayOfWeek).Standard;
            }
            return this.IsStandard(dayOfWeek);
        }

        public bool IsModifiedFromBaseCalendar()
        {
            if (!this.IsBaseCalendar)
            {
                for (int i = 0; i < 7; i++)
                {
                    if ((this._workingDays[i] != null) && !this._workingDays[i].Equals(this._baseCalendar._workingDays[i]))
                    {
                        return true;
                    }
                }
                IList<Period> periods = this.Periods;
                int count = periods.Count;
                for (int j = 0; j < count; j++)
                {
                    if (!periods[j].Standard)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public bool IsModifiedPeriod(DateTime date)
        {
            if (this.IsBaseCalendar)
            {
                return !(this.GetCalendarPeriod(date.Date) is Period);
            }
            CalendarPeriod calendarPeriod = this.GetCalendarPeriod(date.Date);
            if (calendarPeriod is Period)
            {
                return calendarPeriod.Standard;
            }
            return true;
        }

        private bool IsStandard(DayOfWeek dayOfWeek)
        {
            if ((dayOfWeek == DayOfWeek.Saturday) || (dayOfWeek == DayOfWeek.Sunday))
            {
                return !this.GetWorkingDay(dayOfWeek).IsWorking;
            }
            WorkingDay workingDay = this.GetWorkingDay(dayOfWeek);
            return (workingDay.IsWorking && HasStandardWorkingTimes(workingDay));
        }

        public bool IsWorkingDay(DateTime date)
        {
            return this.GetCalendarPeriod(date.Date).IsWorking;
        }

        public bool IsWorkingDay(DayOfWeek dayOfWeek)
        {
            return this.GetWorkingDay(dayOfWeek).IsWorking;
        }

        public DateTime NextNonWorkingTime(DateTime time)
        {
            try
            {
                if (this.HasNextNonWorkingTime(time))
                {
                    bool nonworking = false;
                    while (!nonworking)
                    {
                        Period period = this.GetPeriod(time);
                        if (period != null)
                        {
                            if (period.IsWorking)
                            {
                                time = period.NextNonWorkingTimeFromWT(time, out nonworking);
                                if (!nonworking)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                nonworking = true;
                            }
                        }
                        else
                        {
                            WorkingDay workingDay = this.GetWorkingDay(this._calendar.GetDayOfWeek(time));
                            if (workingDay.IsWorking)
                            {
                                time = workingDay.NextNonWorkingTimeFromWT(time, out nonworking);
                                if (!nonworking)
                                {
                                    continue;
                                }
                            }
                            else
                            {
                                nonworking = true;
                            }
                        }
                        break;
                    }
                }
                return time;
            }
            catch (Exception)
            {
                return DateTime.MaxValue;
            }
        }

        private Period NextPeriod(DateTime t)
        {
            if (this._periods.Count != 0)
            {
                DateTime date = t.Date;
                foreach (Period period in this._periods)
                {
                    if (date <= period.EndDate)
                    {
                        return period;
                    }
                }
            }
            return null;
        }

        public DateTime NextWorkingTime(DateTime time)
        {
            DateTime maxValue;
            try
            {
                bool flag;
                Period period;
                WorkingDay day2;
                if (!this.HasNextWorkingTime(time))
                {
                    return time;
                }
                if (this._periods.Count != 0)
                {
                    goto Label_0067;
                }
            Label_001E:
                do
                {
                    WorkingDay workingDay = this.GetWorkingDay(time.DayOfWeek);
                    if (!workingDay.IsWorking)
                    {
                        goto Label_004A;
                    }
                    time = workingDay.NextWorkingTimeFromWT(time, out flag);
                }
                while (!flag);
                return time;
            Label_004A:
                time = time.Date.AddDays(1.0);
                goto Label_001E;
            Label_0067:
                do
                {
                    period = this.GetPeriod(time);
                    if (period == null)
                    {
                        goto Label_00A9;
                    }
                    if (!period.IsWorking)
                    {
                        goto Label_008D;
                    }
                    time = period.NextWorkingTimeFromWT(time, out flag);
                }
                while (!flag);
                return time;
            Label_008D:
                time = period.EndDate.AddDays(1.0);
                goto Label_0067;
            Label_00A9:
                day2 = this.GetWorkingDay(time.DayOfWeek);
                if (day2.IsWorking)
                {
                    time = day2.NextWorkingTimeFromWT(time, out flag);
                    if (!flag)
                    {
                        goto Label_0067;
                    }
                    maxValue = time;
                }
                else
                {
                    time = time.Date.AddDays(1.0);
                    goto Label_0067;
                }
            }
            catch
            {
                maxValue = DateTime.MaxValue;
            }
            return maxValue;
        }

        private void OnBaseCalendarChanged()
        {
            this.InheritBasePeriods();
            this.OnChanged(EventArgs.Empty);
        }

        public virtual void OnCalendarNameChanged(object sender, EventArgs e)
        {
            if (this._nameChanged != null)
            {
                this._nameChanged(this, e);
            }
        }

        public virtual void OnChanged(EventArgs e)
        {
            if (!this._disableevents)
            {
                if (this._subCalendars != null)
                {
                    WeakReference[] array = new WeakReference[this._subCalendars.Count];
                    this._subCalendars.CopyTo(array);
                    foreach (WeakReference reference in array)
                    {
                        WorkCalendar target = (WorkCalendar) reference.Target;
                        if (target != null)
                        {
                            target.OnBaseCalendarChanged();
                        }
                        else
                        {
                            this._subCalendars.Remove(reference);
                        }
                    }
                }
                if (this._changed != null)
                {
                    this._changed(this, e);
                }
            }
        }

        private Period PreviousPeriod(DateTime t)
        {
            int count = this._periods.Count;
            if (count != 0)
            {
                DateTime date = t.Date;
                for (int i = count - 1; i >= 0; i--)
                {
                    Period period = this._periods[i];
                    if (date > period.StartDate)
                    {
                        return period;
                    }
                }
            }
            return null;
        }

        public DateTime PreviousWorkingTime(DateTime time)
        {
            DateTime minValue;
            try
            {
                bool flag;
                Period periodBackWard;
                WorkingDay day;
                if (!this.HasPreviousWorkingTime(time))
                {
                    return time;
                }
            Label_0010:
                do
                {
                    periodBackWard = this.GetPeriodBackWard(time);
                    if (periodBackWard == null)
                    {
                        goto Label_003F;
                    }
                    if (!periodBackWard.IsWorking)
                    {
                        goto Label_0035;
                    }
                    time = periodBackWard.PreviousWorkingTimeFromWT(time, out flag);
                }
                while (!flag);
                return time;
            Label_0035:
                time = periodBackWard.StartDate;
                goto Label_0010;
            Label_003F:
                day = this.GetWorkingDayBackward(time);
                if (day.IsWorking)
                {
                    time = day.PreviousWorkingTimeFromWT(time, out flag);
                    if (!flag)
                    {
                        goto Label_0010;
                    }
                    minValue = time;
                }
                else
                {
                    if (time == time.Date)
                    {
                        time = time.AddDays(-1.0);
                    }
                    else
                    {
                        time = time.Date;
                    }
                    goto Label_0010;
                }
            }
            catch (Exception)
            {
                minValue = DateTime.MinValue;
            }
            return minValue;
        }

        public DateTime Remove(DateTime time, TimeSpan work)
        {
            try
            {
                long ticks = work.Ticks;
                if (ticks > 0L)
                {
                    goto Label_00F2;
                }
                return time;
            Label_0018:
                time = this.PreviousWorkingTime(time);
                if (!this.HasPreviousWorkingTime(time))
                {
                    return time;
                }
                Period periodBackWard = this.GetPeriodBackWard(time);
                if (periodBackWard != null)
                {
                    time = periodBackWard.Remove(time, ref ticks);
                }
                else
                {
                    periodBackWard = this.PreviousPeriod(time);
                    long duration = ticks;
                    if (periodBackWard != null)
                    {
                        long num3 = this.StandardWorkBetween(periodBackWard.EndDate.AddDays(1.0), time);
                        duration = Math.Min(ticks, num3);
                    }
                    ticks -= duration;
                    long workInOneWeek = this.WorkInOneWeek;
                    if (duration >= workInOneWeek)
                    {
                        long num5 = duration / workInOneWeek;
                        if ((duration % workInOneWeek) == 0L)
                        {
                            num5 -= 1L;
                        }
                        time = time.AddDays((double) (-7L * num5));
                        duration -= num5 * workInOneWeek;
                    }
                    while ((duration != 0L) && (time != DateTime.MinValue))
                    {
                        time = this.PreviousWorkingTime(time);
                        time = this.GetWorkingDayBackward(time).Remove(time, ref duration);
                    }
                }
            Label_00F2:
                if (ticks != 0L)
                {
                    goto Label_0018;
                }
                return time;
            }
            catch (Exception)
            {
                return DateTime.MinValue;
            }
        }

        private void RemoveSubcalendar(WorkCalendar cal)
        {
            if (!this.IsPredefinedCalendar && (this._subCalendars != null))
            {
                foreach (WeakReference reference in this._subCalendars)
                {
                    if (reference.Target == cal)
                    {
                        this._subCalendars.Remove(reference);
                        break;
                    }
                }
            }
        }

        private void ResetBaseCalendar()
        {
            this.BaseCalendar = Standard;
        }

        public void ResetToDefault(DayOfWeek dow)
        {
            this.AssertNotReadOnly();
            if (!this.IsDefaultWorkingDay(dow))
            {
                if (this.IsBaseCalendar)
                {
                    this._workingDays[(int) dow] = CreateDefaultWorkingDay(this, dow);
                    this._workingDays[(int) dow].Standard = true;
                }
                else
                {
                    this._workingDays[(int) dow] = null;
                }
                this.OnChanged(EventArgs.Empty);
            }
        }

        public void ResetToDefault(DateTime start, DateTime end)
        {
            this.AssertNotReadOnly();
            start = start.Date;
            end = end.Date;
            if (end < start)
            {
                throw new ArgumentException("start after end");
            }
            if (this.Periods.Count != 0)
            {
                Period[] array = new Period[this.Periods.Count];
                this.Periods.CopyTo(array, 0);
                foreach (Period period in array)
                {
                    if (period.Intersects(start, end))
                    {
                        int index = this.Periods.IndexOf(period);
                        this.Periods.Remove(period);
                        if (period.StartDate < start)
                        {
                            Period item = (Period) period.Clone();
                            item.EndDate = start.AddDays(-1.0);
                            this.Periods.Insert(index++, item);
                        }
                        if (period.EndDate > end)
                        {
                            Period period3 = (Period) period.Clone();
                            period3.StartDate = end.AddDays(1.0);
                            this.Periods.Insert(index, period3);
                        }
                    }
                }
                if (this._baseCalendar != null)
                {
                    foreach (Period period4 in this._baseCalendar.Periods)
                    {
                        if (!period4.Intersects(start, end))
                        {
                            continue;
                        }
                        Period period5 = (Period) period4.Clone();
                        period5.Standard = true;
                        period5.StartDate = TimeUtil.Max(period4.StartDate, start);
                        period5.EndDate = TimeUtil.Min(period4.EndDate, end);
                        int count = this.Periods.Count;
                        int num3 = 0;
                        foreach (Period period6 in this.Periods)
                        {
                            if (period5.StartDate < period6.StartDate)
                            {
                                count = num3;
                                break;
                            }
                            num3++;
                        }
                        this.Periods.Insert(count, period5);
                    }
                }
                this.OnChanged(EventArgs.Empty);
            }
        }

        private static bool SamePeriods(IList<Period> a, IList<Period> b)
        {
            if (a.Count != b.Count)
            {
                return false;
            }
            for (int i = 0; i < a.Count; i++)
            {
                if (!a[i].Equals(b[i]))
                {
                    return false;
                }
            }
            return true;
        }

        private static bool SameWorkingDays(WorkingDay[] a, WorkingDay[] b)
        {
            for (int i = 0; i < 7; i++)
            {
                if ((a[i] != null) || (b[i] != null))
                {
                    if ((a[i] != null) && (b[i] == null))
                    {
                        return false;
                    }
                    if ((a[i] == null) && (b[i] != null))
                    {
                        return false;
                    }
                    if (!a[i].Equals(b[i]))
                    {
                        return false;
                    }
                }
            }
            return true;
        }

        public void SetNonWorking(DayOfWeek dayOfWeek)
        {
            this.AssertNotReadOnly();
            this._workingDays[(int) dayOfWeek] = new WorkingDay(this, false, dayOfWeek);
            this.OnChanged(EventArgs.Empty);
        }

        public void SetNonWorking(DateTime from, DateTime to)
        {
            this.AssertNotReadOnly();
            from = from.Date;
            to = to.Date;
            Period item = new Period(this, false, from, to);
            if (this.Periods.Count == 0)
            {
                this.Periods.Add(item);
            }
            else
            {
                Period[] array = new Period[this.Periods.Count];
                this.Periods.CopyTo(array, 0);
                List<Period> list = new List<Period>();
                foreach (Period period2 in array)
                {
                    if (!period2.IsWorking)
                    {
                        if ((period2.Intersects(item) || (period2.EndDate.AddDays(1.0) == item.StartDate)) || (item.EndDate.AddDays(1.0) == period2.StartDate))
                        {
                            if (!period2.Standard)
                            {
                                item.StartDate = TimeUtil.Min(period2.StartDate, item.StartDate);
                                item.EndDate = TimeUtil.Max(period2.EndDate, item.EndDate);
                            }
                            else
                            {
                                if (period2.StartDate < item.StartDate)
                                {
                                    Period period3 = (Period) period2.Clone();
                                    period3.EndDate = item.StartDate.AddDays(-1.0);
                                    list.Add(period3);
                                }
                                if (period2.EndDate > item.EndDate)
                                {
                                    Period period4 = (Period) period2.Clone();
                                    period4.StartDate = item.EndDate.AddDays(1.0);
                                    list.Add(period4);
                                }
                            }
                        }
                        else
                        {
                            list.Add(period2);
                        }
                    }
                    else if (period2.Intersects(item))
                    {
                        if (period2.StartDate < item.StartDate)
                        {
                            Period period5 = (Period) period2.Clone();
                            period5.EndDate = item.StartDate.AddDays(-1.0);
                            list.Add(period5);
                        }
                        if (period2.EndDate > item.EndDate)
                        {
                            Period period6 = (Period) period2.Clone();
                            period6.StartDate = item.EndDate.AddDays(1.0);
                            list.Add(period6);
                        }
                    }
                    else
                    {
                        list.Add(period2);
                    }
                }
                int index = 0;
                bool flag = false;
                foreach (Period period7 in list)
                {
                    if (item.EndDate < period7.EndDate)
                    {
                        list.Insert(index, item);
                        flag = true;
                        break;
                    }
                    index++;
                }
                if (!flag)
                {
                    list.Add(item);
                }
                this.Periods.Clear();
                foreach (Period period8 in list)
                {
                    this.Periods.Add(period8);
                }
            }
            this.OnChanged(EventArgs.Empty);
        }

        public void SetWorkingTimes(DayOfWeek dayOfWeek, WorkingTime[] times)
        {
            this.AssertNotReadOnly();
            WorkingDay day = new WorkingDay(this, true, dayOfWeek);
            if ((times != null) && (times.Length != 0))
            {
                CheckWorkingTimes(times);
                day.WorkingTimes.Clear();
                for (int i = 0; i < times.Length; i++)
                {
                    day.WorkingTimes.Add(times[i].Clone() as WorkingTime);
                }
            }
            this._workingDays[(int) dayOfWeek] = day;
            this.OnChanged(EventArgs.Empty);
        }

        public void SetWorkingTimes(DateTime from, DateTime to, WorkingTime[] times)
        {
            this.AssertNotReadOnly();
            from = from.Date;
            to = to.Date;
            Period item = new Period(this, true, from, to);
            if ((times != null) && (times.Length != 0))
            {
                CheckWorkingTimes(times);
                item.WorkingTimes.Clear();
                foreach (WorkingTime time in times)
                {
                    item.WorkingTimes.Add(time.Clone() as WorkingTime);
                }
            }
            if (this.Periods.Count == 0)
            {
                this.Periods.Add(item);
            }
            else
            {
                Period[] array = new Period[this.Periods.Count];
                this.Periods.CopyTo(array, 0);
                List<Period> list = new List<Period>();
                foreach (Period period2 in array)
                {
                    if (period2.IsWorking)
                    {
                        if ((item.Intersects(period2) || (period2.EndDate.AddDays(1.0) == item.StartDate)) || (item.EndDate.AddDays(1.0) == period2.StartDate))
                        {
                            if (!period2.Standard && item.SameWorkingTimes(period2))
                            {
                                item.StartDate = TimeUtil.Min(period2.StartDate, item.StartDate);
                                item.EndDate = TimeUtil.Max(period2.EndDate, item.EndDate);
                            }
                            else
                            {
                                if (period2.StartDate < item.StartDate)
                                {
                                    Period period3 = (Period) period2.Clone();
                                    period3.EndDate = item.StartDate.AddDays(-1.0);
                                    list.Add(period3);
                                }
                                if (period2.EndDate > item.EndDate)
                                {
                                    Period period4 = (Period) period2.Clone();
                                    period4.StartDate = item.EndDate.AddDays(1.0);
                                    list.Add(period4);
                                }
                            }
                        }
                        else
                        {
                            list.Add(period2);
                        }
                    }
                    else if (period2.Intersects(item))
                    {
                        if (period2.StartDate < item.StartDate)
                        {
                            Period period5 = (Period) period2.Clone();
                            period5.EndDate = item.StartDate.AddDays(-1.0);
                            list.Add(period5);
                        }
                        if (period2.EndDate > item.EndDate)
                        {
                            Period period6 = (Period) period2.Clone();
                            period6.StartDate = item.EndDate.AddDays(1.0);
                            list.Add(period6);
                        }
                    }
                    else
                    {
                        list.Add(period2);
                    }
                }
                int index = 0;
                bool flag = false;
                foreach (Period period7 in list)
                {
                    if (item.EndDate < period7.EndDate)
                    {
                        list.Insert(index, item);
                        flag = true;
                        break;
                    }
                    index++;
                }
                if (!flag)
                {
                    list.Add(item);
                }
                this.Periods.Clear();
                foreach (Period period8 in list)
                {
                    this.Periods.Add(period8);
                }
            }
            this.OnChanged(EventArgs.Empty);
        }

        private bool ShouldSerializeBaseCalendar()
        {
            return (this.BaseCalendar != Standard);
        }

        private long StandardWorkBetween(DateTime t1, DateTime t2)
        {
            if (t1 > t2)
            {
                throw new ArgumentException();
            }
            if (t1 == t2)
            {
                return 0L;
            }
            WorkingDay workingDay = this.GetWorkingDay(t1);
            DateTime date = t1.Date;
            DateTime time2 = t2.Date;
            DateTime end = date.AddDays(1.0);
            if ((t1.Date == t2.Date) || (t2 == end))
            {
                return workingDay.WorkBetween(t1, t2);
            }
            long num = workingDay.WorkBetween(t1, end);
            DateTime time = end;
            TimeSpan span = (TimeSpan) (t2.Date - time.Date);
            int num3 = span.Days / 7;
            num += num3 * this.WorkInOneWeek;
            time = time.AddDays((double) (num3 * 7));
            while (time < time2)
            {
                end = time.AddDays(1.0);
                workingDay = this.GetWorkingDay(time);
                num += workingDay.WorkBetween(time, end);
                time = end;
            }
            if (t2 > time)
            {
                workingDay = this.GetWorkingDay(time);
                num += workingDay.WorkBetween(time, t2);
            }
            return num;
        }

        public override string ToString()
        {
            if (!this.IsBaseCalendar)
            {
                return (this.CalendarName + " based on " + this.BaseCalendar.CalendarName);
            }
            return this.CalendarName;
        }

        public TimeSpan WorkBetween(DateTime t1, DateTime t2)
        {
            bool flag = false;
            if (t2 < t1)
            {
                DateTime time = t1;
                t1 = t2;
                t2 = time;
                flag = true;
            }
            if (t1 == t2)
            {
                return TimeSpan.Zero;
            }
            if (t1.Date == t2.Date)
            {
                CalendarPeriod calendarPeriod = this.GetCalendarPeriod(t1.Date);
                if (!calendarPeriod.IsWorking)
                {
                    return TimeSpan.Zero;
                }
                long num = calendarPeriod.WorkBetweenHours(t1, t2);
                return TimeSpan.FromTicks(flag ? -num : num);
            }
            long num2 = 0L;
            t1 = this.NextWorkingTime(t1);
            t2 = this.PreviousWorkingTime(t2);
            if (t1 >= t2)
            {
                return TimeSpan.Zero;
            }
            while (true)
            {
                Period period2 = this.NextPeriod(t1);
                if (period2 == null)
                {
                    break;
                }
                if (t2.Date < period2.StartDate)
                {
                    num2 += this.StandardWorkBetween(t1, t2);
                    goto Label_016B;
                }
                if (t1 < period2.StartDate)
                {
                    num2 += this.StandardWorkBetween(t1, period2.StartDate);
                    t1 = period2.StartDate;
                }
                if (t2.Date <= period2.EndDate)
                {
                    num2 += period2.WorkBetween(t1, t2);
                    goto Label_016B;
                }
                num2 += period2.WorkBetween(t1, period2.EndDate.AddDays(1.0));
                t1 = period2.EndDate.AddDays(1.0);
            }
            num2 += this.StandardWorkBetween(t1, t2);
        Label_016B:
            return TimeSpan.FromTicks(flag ? -num2 : num2);
        }

        [Category("Data"), TypeConverter("ILOG.Views.Gantt.Windows.Forms.Design.BaseCalendarReferenceConverter, ILOG.Gantt.Design, Version=3.5.0.0, Culture=neutral, PublicKeyToken=7906592bc7cc7340"), Description("The base calendar from which this calendar inherits its description")]
        public WorkCalendar BaseCalendar
        {
            get
            {
                return this._baseCalendar;
            }
            set
            {
                this.AssertNotReadOnly();
                if ((value != null) && (value == this))
                {
                    throw new ArgumentException("The base calendar cannot be this calendar");
                }
                if ((value != null) && !value.IsBaseCalendar)
                {
                    if (!value._initializing)
                    {
                        throw new ArgumentException("The calendar is not a base calendar");
                    }
                    value.BaseCalendar = null;
                }
                if (value != this.BaseCalendar)
                {
                    if (this.IsBaseCalendar)
                    {
                        if (this._subCalendars != null)
                        {
                            WeakReference[] referenceArray = this._subCalendars.ToArray();
                            this._subCalendars.Clear();
                            foreach (WeakReference reference in referenceArray)
                            {
                                WorkCalendar target = (WorkCalendar) reference.Target;
                                if (target != null)
                                {
                                    target.BaseCalendar = Standard;
                                }
                            }
                        }
                        for (int i = 0; i < 7; i++)
                        {
                            WorkingDay day = this._workingDays[i];
                            if (day.Equals(value._workingDays[i]))
                            {
                                this._workingDays[i] = null;
                            }
                            else if (this.IsStandard((DayOfWeek) i))
                            {
                                this._workingDays[i] = null;
                            }
                            else
                            {
                                this._workingDays[i].Standard = false;
                            }
                        }
                        foreach (Period period in this._periods)
                        {
                            period.Standard = false;
                        }
                        this._baseCalendar = value;
                        this._baseCalendar.AddSubcalendar(this);
                        this.InheritBasePeriods();
                    }
                    else
                    {
                        this._baseCalendar.RemoveSubcalendar(this);
                        if (value == null)
                        {
                            for (int j = 0; j < 7; j++)
                            {
                                if (this._workingDays[j] == null)
                                {
                                    this._workingDays[j] = CreateDefaultWorkingDay(this, (DayOfWeek) j);
                                }
                                this._workingDays[j].Standard = true;
                            }
                            Period[] array = new Period[this._periods.Count];
                            this._periods.CopyTo(array);
                            foreach (Period period2 in array)
                            {
                                if (period2.Standard)
                                {
                                    this._periods.Remove(period2);
                                }
                            }
                            this._baseCalendar = null;
                        }
                        else
                        {
                            this._baseCalendar = value;
                            this._baseCalendar.AddSubcalendar(this);
                            this.InheritBasePeriods();
                        }
                    }
                    this.OnChanged(EventArgs.Empty);
                }
            }
        }

        [Description("The name of the calendar"), DefaultValue("Default"), Category("Data")]
        public string CalendarName
        {
            get
            {
                if (this._name != null)
                {
                    return this._name;
                }
                return string.Empty;
            }
            set
            {
                this.AssertNotReadOnly();
                if (this._name != value)
                {
                    this._name = value;
                    this.OnCalendarNameChanged(this, EventArgs.Empty);
                }
            }
        }

        public bool IsBaseCalendar
        {
            get
            {
                return (this._baseCalendar == null);
            }
        }

        public bool IsPredefinedCalendar
        {
            get
            {
                if ((this != Standard) && (this != TwentyFourHours))
                {
                    return (this == NightShift);
                }
                return true;
            }
        }

        private IList<Period> Periods
        {
            get
            {
                return this._periods;
            }
        }

        private long WorkInOneWeek
        {
            get
            {
                long num = 0L;
                for (int i = 0; i < 7; i++)
                {
                    num += this.GetWorkingDay((DayOfWeek) i).WorkInOneDay;
                }
                return num;
            }
        }
    }
}

